package com.ddh.codeduck.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.codeduck.pojo.dto.CodeDuckQuestionCategoryDTO;
import com.codeduck.pojo.entity.CodeDuckQuestionCategory;
import com.codeduck.pojo.entity.CodeDuckQuestionCategoryTag;
import com.codeduck.pojo.entity.CodeDuckTag;
import com.ddh.codeduck.mapper.CodeDuckQuestionCategoryMapper;
import com.codeduck.pojo.req.CodeDuckQuestionCategoryPageReq;
import com.ddh.codeduck.service.ICodeDuckQuestionCategoryService;
import com.ddh.codeduck.service.ICodeDuckQuestionCategoryTagService;
import com.ddh.codeduck.service.ICodeDuckTagService;
import com.codeduck.pojo.vo.CodeDuckQuestionCategoryVO;
import com.ddhcodeduck.common.exception.BusinessException;
import com.ddhcodeduck.common.exception.ErrorCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 题目分类表 服务实现类
 * </p>
 *
 * @author ddh
 * @since 2025-07-03
 */
@Service
@Slf4j
public class CodeDuckQuestionCategoryServiceImpl extends ServiceImpl<CodeDuckQuestionCategoryMapper, CodeDuckQuestionCategory> implements ICodeDuckQuestionCategoryService {

    @Resource
    private ICodeDuckQuestionCategoryTagService codeDuckQuestionCategoryTagService;

    @Resource
    private ICodeDuckTagService codeDuckTagService;

    /**
     * 列表题目分类
     *
     * @param codeDuckQuestionCategoryPageReq
     * @return
     */
    @Override
    public IPage<CodeDuckQuestionCategoryVO> listQuestionCategory(CodeDuckQuestionCategoryPageReq codeDuckQuestionCategoryPageReq) {
        log.info("listQuestionCategory:{}", codeDuckQuestionCategoryPageReq);
        // 创建 Page 对象，传入当前页和页面大小
        Integer current = codeDuckQuestionCategoryPageReq.getCurrent(); // 改为 Integer 类型
        Integer pageSize = codeDuckQuestionCategoryPageReq.getPageSize(); // 改为 Integer 类型
        String sortOrder = codeDuckQuestionCategoryPageReq.getSortOrder();
        // 题目分类名称
        String name = codeDuckQuestionCategoryPageReq.getName();
        // 标签ids
        List<String> tagIds = codeDuckQuestionCategoryPageReq.getTagIds();

        LambdaQueryWrapper<CodeDuckQuestionCategory> queryWrapper = new LambdaQueryWrapper<>();
        if (CollectionUtil.isNotEmpty(tagIds)) {
            List<CodeDuckQuestionCategoryTag> codeDuckQuestionCategoryTags = codeDuckQuestionCategoryTagService.listByIds(tagIds);
            //检验一下这些标签是不是都是二级标签，parentId不为空或者空串
            codeDuckQuestionCategoryTags.forEach(codeDuckQuestionCategoryTag -> {
                CodeDuckTag codeDuckTag = codeDuckTagService.getById(codeDuckQuestionCategoryTag.getTagId());
                if (codeDuckTag == null) {
                    throw new BusinessException(ErrorCode.QUESTION_TAG_NOT_SECOND_LEVEL_ERROR);
                }
            });
            // 分类ids
            List<String> ids = codeDuckQuestionCategoryTags.stream().map(CodeDuckQuestionCategoryTag::getCategoryId).collect(Collectors.toList());
            queryWrapper.in(CollUtil.isNotEmpty(ids), CodeDuckQuestionCategory::getId, ids);
        }
        queryWrapper.like(StringUtils.isNotBlank(name), CodeDuckQuestionCategory::getName, name);
        // 给题目分类加一个排序sort
        if ("asc".equals(sortOrder)) {
            queryWrapper.orderByAsc(CodeDuckQuestionCategory::getSort);
        } else if ("desc".equals(sortOrder)) {
            queryWrapper.orderByDesc(CodeDuckQuestionCategory::getSort);
        } else {
            // 虽然有默认值，但是还是写上这个啥也不输入就是升序
            queryWrapper.orderByAsc(CodeDuckQuestionCategory::getSort);
        }

        IPage<CodeDuckQuestionCategory> questionCategoryPage;
        if (current == null || pageSize == null) {
            // 不分页，查询所有数据
            List<CodeDuckQuestionCategory> categoryList = list(queryWrapper);
            questionCategoryPage = new Page<CodeDuckQuestionCategory>().setRecords(categoryList).setSize(categoryList.size()).setCurrent(1).setTotal(categoryList.size());
        } else {
            // 分页查询
            Page<CodeDuckQuestionCategory> page = new Page<>(current, pageSize);
            questionCategoryPage = page(page, queryWrapper);
        }

        IPage<CodeDuckQuestionCategoryVO> codeDuckQuestionCategoryVOIPage = questionCategoryPage.convert(entity -> {
            CodeDuckQuestionCategoryVO vo = new CodeDuckQuestionCategoryVO();
            BeanUtils.copyProperties(entity, vo);
            String categoryQuestionId = vo.getId();
            List<CodeDuckQuestionCategoryTag> codeDuckQuestionCategoryTagList = codeDuckQuestionCategoryTagService.list(new LambdaQueryWrapper<CodeDuckQuestionCategoryTag>().eq(CodeDuckQuestionCategoryTag::getCategoryId, categoryQuestionId));
            List<String> tagIdList = codeDuckQuestionCategoryTagList.stream().map(CodeDuckQuestionCategoryTag::getTagId).collect(Collectors.toList());
            vo.setTagIdList(tagIdList);
            //根据标签id查询标签名称集合
            if (CollectionUtil.isNotEmpty(tagIdList)) {
                List<CodeDuckTag> codeDuckTags = codeDuckTagService.listByIds(tagIdList);
                List<String> tagNameList = codeDuckTags.stream().map(CodeDuckTag::getName).collect(Collectors.toList());
                vo.setTagNameList(tagNameList);
            }
            return vo;
        });
        return codeDuckQuestionCategoryVOIPage;
    }

    /**
     * 新增或修改题目分类
     *
     * @param codeDuckQuestionCategoryDTO
     * @return
     */
    @Override
    @Transactional
    public boolean mySaveOrUpdate(CodeDuckQuestionCategoryDTO codeDuckQuestionCategoryDTO) {
        // 1. 将 DTO 转换为 Entity
        CodeDuckQuestionCategory codeDuckQuestionCategory = new CodeDuckQuestionCategory();
        BeanUtils.copyProperties(codeDuckQuestionCategoryDTO, codeDuckQuestionCategory);

        // 2. 保存或更新题目分类
        boolean saveOrUpdate = saveOrUpdate(codeDuckQuestionCategory);
        if (!saveOrUpdate) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR);
        }

        // 3. 获取当前题目分类的 ID
        String categoryId = codeDuckQuestionCategory.getId();

        // 4. 获取 DTO 中的标签 ID 列表
        List<String> newTagIdList = codeDuckQuestionCategoryDTO.getTagIdList();
        if (CollectionUtil.isEmpty(newTagIdList)) {
            throw new BusinessException(ErrorCode.TAG_ID_NOT_NULL_ERROR);
        }

        // 5. 获取当前题目分类已有的标签 ID 列表
        List<CodeDuckQuestionCategoryTag> existingTags = codeDuckQuestionCategoryTagService.list(
                new LambdaQueryWrapper<CodeDuckQuestionCategoryTag>()
                        .eq(CodeDuckQuestionCategoryTag::getCategoryId, categoryId)
        );
        List<String> existingTagIdList = existingTags.stream()
                .map(CodeDuckQuestionCategoryTag::getTagId)
                .collect(Collectors.toList());

        // 6. 需要插入的新标签 ID 列表
        List<String> tagsToAdd = new ArrayList<>(newTagIdList);
        tagsToAdd.removeAll(existingTagIdList);

        // 7. 需要删除的旧标签 ID 列表
        List<String> tagsToRemove = new ArrayList<>(existingTagIdList);
        tagsToRemove.removeAll(newTagIdList);

        // 8. 插入新标签
        for (String tagId : tagsToAdd) {
            CodeDuckQuestionCategoryTag codeDuckQuestionCategoryTag = new CodeDuckQuestionCategoryTag();
            codeDuckQuestionCategoryTag.setCategoryId(categoryId);
            codeDuckQuestionCategoryTag.setTagId(tagId);
            codeDuckQuestionCategoryTagService.save(codeDuckQuestionCategoryTag);
        }

        // 9. 删除旧标签
        if (!tagsToRemove.isEmpty()) {
            codeDuckQuestionCategoryTagService.remove(
                    new LambdaQueryWrapper<CodeDuckQuestionCategoryTag>()
                            .eq(CodeDuckQuestionCategoryTag::getCategoryId, categoryId)
                            .in(CodeDuckQuestionCategoryTag::getTagId, tagsToRemove)
            );
        }

        return true;
    }

}
